//
// Created by Eric on 2023/1/23.
// 管理天体和文明之间拥有关系的数据库
//

#ifndef UUU_RELATIONMATRIX_H
#define UUU_RELATIONMATRIX_H
#include <vector>
#include "uuu_utility.h"
#include "Counter.h"
#include <iomanip>

class RelationMatrix {
public:
    // 在观测角度上，文明和天体的关系
    enum OBSTATE{
        OWN             = 0x00000011, // 拥有
        KNOW            = 0x00000001, // 已发现
        UNKNOWN         = 0x00000000, // 未发现
        MOTHERLAND      = 0x00000111, // 母星
    };

    // 关系结构体，以后会加别的东西
    struct Relation{
        OBSTATE obstate;
        Relation(){
            obstate = UNKNOWN;
        }
    };
public:
    // getter&setter
    auto matrix() {
        return matrix_;
    }
    auto civilization_own_asobjects(){
        return civilization_own_asobjects_;
    }
    auto asobject_owner_civilization(){
        return asobject_owner_civilization_;
    }

public:
    // api
    void Display(){
        auto noc = p_dbi_->num_of_civilization;
        auto noa = p_dbi_->num_of_asobject;
        cout << setw(12) << left << " " ;
        for(int i = 0 ; i < noa;i++){
            cout << setw(12)  <<left<< i;
        }
        cout <<endl;
        for(int i = 0; i < noc;i++){
            cout << setw(12) << left<< i ;
            for(int j = 0; j < noa;j++){
                if(matrix_[i][j].obstate == OWN){
                    cout << setw(12) <<left<<"OWN";
                }
                else if(matrix_[i][j].obstate == KNOW){
                    cout << setw(12) << left << "KNOW";
                }
                else if(matrix_[i][j].obstate == UNKNOWN){
                    cout << setw(12) << left << "UNKNOWN";
                }
                else if(matrix_[i][j].obstate == MOTHERLAND){
                    cout << setw(12) << left << "MOTHERLAND";
                }
                else
                    cout<<setw(12 )<<left <<"ERROR";
            }
            cout <<endl;
        }
    }

    // 直接设置拥有关系
    void SetObState(int source, int target, OBSTATE obstate);

    // 获取idx为lhs的文明对idx为rhs的天体的观测情况
    OBSTATE GetObState(int lhs, int rhs){ return matrix_[lhs][rhs].obstate; }

    // 获取控制该天体的文明编号 若没有文明控制则返回-1
    int GetAoOwnerId(int asobject_idx);

    // 获取文明拥有的天体的idx数组
    vector<int> GetCivilizationOwnAsObjectIdx(int civilization_idx);

    // 获取文明已经探测到的天体的idx数组 就是星图
    vector<int> GetCzStarMap(int civilization_idx);

private:
    // data
    std::vector<std::vector<Relation>> matrix_; // 关系矩阵的核心数据结构
    // about matrix:
    // 行号代表cz_idx，列号代表ao_idx


    std::vector<std::vector<int>> civilization_own_asobjects_; // 文明拥有的天体索引列表、依赖于matrix
    std::vector<int> asobject_owner_civilization_; // 天体的支配文明列表、依赖于matrix


    DatabaseInfo* p_dbi_;


public:
    // 构造方法
    RelationMatrix();
    void Initialize(DatabaseInfo* p_dbi);
};

RelationMatrix::RelationMatrix() {
}

vector<int> RelationMatrix::GetCzStarMap(int civilization_idx){
    auto tmp = matrix_[civilization_idx];
    auto n = tmp.size();
    vector<int> res;
    for(int i = 0; i < n;i++){
        if(tmp[i].obstate & KNOW){
            res.push_back(i);
        }
    }

    return res;
}

void RelationMatrix::Initialize(DatabaseInfo* p_dbi) {
    p_dbi_ = p_dbi;
    auto noc = p_dbi->num_of_civilization;
    auto noa = p_dbi->num_of_asobject;

    // 初始化关系矩阵
    matrix_.resize(noc, std::vector<Relation>(noa));

    // 设置拥有关系
    for(int cz_idx = 0; cz_idx < matrix_.size();cz_idx++) {
        for (int ao_idx = 0; ao_idx < matrix_[0].size(); ao_idx++) {
            if (cz_idx == ao_idx) {
                matrix_[cz_idx][ao_idx].obstate = MOTHERLAND;
                continue;
            }
        }
    }
}

// 设置拥有关系
void RelationMatrix::SetObState(int source, int target, OBSTATE obstate) {
    matrix_[source][target].obstate = obstate;
}

// 获取拥有该天体的文明编号
int RelationMatrix::GetAoOwnerId(int asobject_idx) {
    for(int i = 0; i < p_dbi_->num_of_civilization; i++){
        if(matrix_[i][asobject_idx].obstate == OWN){
            return i;
        }
    }
    return -1;
}


// 获取该文明所有拥有天体的编号数组
vector<int> RelationMatrix::GetCivilizationOwnAsObjectIdx(int civilization_idx) {
    vector<int> res;
    for(int i =0 ;i < p_dbi_->num_of_asobject;i++){
        if(matrix_[civilization_idx][i].obstate == OWN) {
            res.push_back(i);
        }
    }
    return res;
}

#endif //UUU_RELATIONMATRIX_H
